package threadlocal;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.threadpool.TtlExecutors;

/**
 * @author chaird
 * @create 2021-05-13 20:14
 */
public class TransmittableThreadLocalDemo {
  public static void main(String[] args) {
    // 需要注意的是，使用TTL的时候，要想传递的值不出问题，线程池必须得用TTL加一层代理（下面会讲这样做的目的）
    ExecutorService executorService =
        TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(2));
    // 这里采用TTL的实现
    ThreadLocal tl = new TransmittableThreadLocal<>();
    new Thread(
            () -> {
              String mainThreadName = "main_01";

              tl.set(1);

              executorService.execute(
                  () -> {
                    sleep(1L);
                    System.out.println(
                        String.format(
                            "本地变量改变之前(1), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                            mainThreadName, Thread.currentThread().getName(), tl.get()));
                  });

              executorService.execute(
                  () -> {
                    sleep(1L);
                    System.out.println(
                        String.format(
                            "本地变量改变之前(1), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                            mainThreadName, Thread.currentThread().getName(), tl.get()));
                  });

              executorService.execute(
                  () -> {
                    sleep(1L);
                    System.out.println(
                        String.format(
                            "本地变量改变之前(1), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                            mainThreadName, Thread.currentThread().getName(), tl.get()));
                  });

              sleep(1L); // 确保上面的会在tl.set执行之前执行
              tl.set(2); // 等上面的线程池第一次启用完了，父线程再给自己赋值

              executorService.execute(
                  () -> {
                    sleep(1L);
                    System.out.println(
                        String.format(
                            "本地变量改变之后(2), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                            mainThreadName, Thread.currentThread().getName(), tl.get()));
                  });

              executorService.execute(
                  () -> {
                    sleep(1L);
                    System.out.println(
                        String.format(
                            "本地变量改变之后(2), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                            mainThreadName, Thread.currentThread().getName(), tl.get()));
                  });

              executorService.execute(
                  () -> {
                    sleep(1L);
                    System.out.println(
                        String.format(
                            "本地变量改变之后(2), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                            mainThreadName, Thread.currentThread().getName(), tl.get()));
                  });

//              System.out.println(
//                  String.format("线程名称-%s, 变量值=%s", Thread.currentThread().getName(), tl.get()));
            })
        .start();

    new Thread(
            () -> {
              String mainThreadName = "main_02";

              tl.set(3);

              executorService.execute(
                  () -> {
                    sleep(1L);
                    System.out.println(
                        String.format(
                            "本地变量改变之前(3), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                            mainThreadName, Thread.currentThread().getName(), tl.get()));
                  });

              executorService.execute(
                  () -> {
                    sleep(1L);
                    System.out.println(
                        String.format(
                            "本地变量改变之前(3), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                            mainThreadName, Thread.currentThread().getName(), tl.get()));
                  });

              executorService.execute(
                  () -> {
                    sleep(1L);
                    System.out.println(
                        String.format(
                            "本地变量改变之前(3), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                            mainThreadName, Thread.currentThread().getName(), tl.get()));
                  });

              sleep(1L); // 确保上面的会在tl.set执行之前执行
              tl.set(4); // 等上面的线程池第一次启用完了，父线程再给自己赋值

              executorService.execute(
                  () -> {
                    sleep(1L);
                    System.out.println(
                        String.format(
                            "本地变量改变之后(4), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                            mainThreadName, Thread.currentThread().getName(), tl.get()));
                  });

              executorService.execute(
                  () -> {
                    sleep(1L);
                    System.out.println(
                        String.format(
                            "本地变量改变之后(4), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                            mainThreadName, Thread.currentThread().getName(), tl.get()));
                  });

              executorService.execute(
                  () -> {
                    sleep(1L);
                    System.out.println(
                        String.format(
                            "本地变量改变之后(4), 父线程名称-%s, 子线程名称-%s, 变量值=%s",
                            mainThreadName, Thread.currentThread().getName(), tl.get()));
                  });

//              System.out.println(
//                  String.format("线程名称-%s, 变量值=%s", Thread.currentThread().getName(), tl.get()));
            })
        .start();
  }

  private static void sleep(long time) {
    try {
      Thread.sleep(time);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
